package net.meddeb.ppmessenger;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import net.meddeb.japptools.Serverconf;

import org.apache.log4j.Logger;


public class Messenger {
	private static final String MSGTYPE_TAG = "msgType";
	private static final String SENDERID_TAG = "senderID";
	private String senderID = "";
	private Logger logger = Logger.getLogger(this.getClass());
	private String topicName = "java:pwdQualityParams";
	private InitialContext jndiContext = null;
	private Topic topic = null;
	private ConnectionFactory connectionFactory = null;	
	private Connection connection = null;
	private Properties props =  null;
	private boolean listening = false;
	private boolean connected = false;
	//listen fields
	private Session session = null;
	private MessageConsumer consumer = null;
	
	@SuppressWarnings("finally")
	private String getHostname(){
		String rslt = "";
		try {
			rslt = InetAddress.getLocalHost().getCanonicalHostName();
		} catch (UnknownHostException e) {
			rslt="";
		} finally{
			if (rslt == null) rslt = "";
			return rslt;
		}
	}
	
	private class ParamsListener implements MessageListener{
		public void onMessage(Message message) {
			logger.debug("Receives a message.");
			TextMessage msg = null;
			try {
				if (message instanceof TextMessage) {
					msg = (TextMessage) message;
					logger.info("Message received: " + msg.getText());
					if (msg.getStringProperty(MSGTYPE_TAG).equalsIgnoreCase("REQ-TEST-PWDQP")){
						doSend("OK-OK-OK", "RES-TEST-PWDQP");
					}
				} else {
					logger.info("The message type is not supported: " + message.getClass().getName());
				}
			} catch (JMSException e) {
				logger.error("JMSException in onMessage(): " + e.toString());
			} catch (Throwable t) {
				logger.error("Exception in onMessage():" + t.getMessage());
			}
		}
	}
	
	public Messenger(Serverconf serverConf) {
		senderID = getHostname();
		listening = false;
		props = new Properties();
		String tcpUrl = "tcp://" + serverConf.getHost() + ":" + serverConf.getPort();
		String asUrl = "http://" + serverConf.getHost() + ":8080/tomee/ejb";
		System.setProperty("udmbConnectionFactory", 
				"connectionfactory:org.apache.activemq.ActiveMQConnectionFactory:" + tcpUrl);
		System.setProperty("pwdQualityParams", "topic:org.apache.activemq.command.ActiveMQTopic:pwdQualityParams");
		props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.RemoteInitialContextFactory");
		props.put(Context.PROVIDER_URL, asUrl);
		props.put(Context.SECURITY_PRINCIPAL, serverConf.getLogin()); 
		props.put(Context.SECURITY_CREDENTIALS, serverConf.getPassword()); 
	}
	
	@SuppressWarnings("finally")
	public boolean connect(){
		connected = false;
		logger.debug("Connecting to JMS server..");
		try {
			jndiContext = new InitialContext(props);
			connectionFactory = (ConnectionFactory)jndiContext.lookup("java:udmbConnectionFactory");
			logger.debug("ConnectionFactory initialized.");
			connection = connectionFactory.createConnection();
			logger.debug("connection created: " + connection.getClientID());
			connection.setExceptionListener(new ExceptionListener() {
				@Override
				public void onException(JMSException e) {
					listening = false;
					logger.error("Connection error occured: " + e.getMessage());
					logger.error("Stops the listening.");
				}
			});
			topic = (Topic)jndiContext.lookup(topicName);
			logger.debug("Topic found: " + topic.getTopicName());
			connected = (connection != null) && (topic != null);
			if (connected) logger.debug("Messenger successfully connected: " + jndiContext.getNameInNamespace());
		} catch (NamingException e) {
			logger.error("Error when initializing receiver: " + e.getMessage());
		} catch (JMSException e) {
			logger.error("Error when initializing receiver: " + e.getMessage());
		} finally{
			return connected;
		}
	}
	
	@SuppressWarnings("finally")
	public boolean doListen(){
		listening = false;
		if (!connected) return listening;
		String selectCondition = "(" + MSGTYPE_TAG + " = 'REQ-TEST-PWDQP' OR " + 
															MSGTYPE_TAG + " = 'REQ-READ-PWDQP' OR " +
															MSGTYPE_TAG + " = 'REQ-WRITE-PWDQP') AND " +
															"(" + SENDERID_TAG + " <> '" + senderID + "')";
		try {
			connection.start();
			session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
			consumer = session.createConsumer(topic, selectCondition);
			consumer.setMessageListener(new ParamsListener());
			listening = true;
		} catch (JMSException e) {
			logger.error("Listen error: " + e.getMessage());
		} finally {
			return listening;
		}
		
	}
	
	public void stopListen(){
		try{
			if ((listening) && (connection != null)) {
				connection.close();
				consumer = null;
				session.close();
			}
		} catch (JMSException e) {
			logger.error("Error when stops listening: " + e.getMessage());
		}
	}

	public void doSend(String message, String msgType){
		if ((connection == null) || (!connected) || (session == null)) return;
		logger.debug("Sending a message.");
		try{
			MessageProducer producer = session.createProducer(topic);
			TextMessage msg  = session.createTextMessage();
			msg.setStringProperty(MSGTYPE_TAG, msgType);
			msg.setStringProperty(SENDERID_TAG, senderID);
			msg.setText(message);
			logger.info("Sends message: " + msg.getText());
			producer.send(msg);
			logger.debug("Message sent.");
		} catch (JMSException e){
			logger.error(e.getMessage());
		}
	}
	
	public boolean isListening() {
		return listening;
	}

}
